#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <sys/stat.h>
#include <unistd.h>

#include <delete_timer.h>
#include <flache.h>
#include <file_cache.h>
#include <flache_debug.h>
#include <flache_rsync.h>
#include <connection_monitor.h>

// This will fail (or not work properly) if server_path is not
// the mountpoint (that is, if you're using links in some funky way).
//
// Also, if there are spaces in the mount point, this will not work properly
// 
// also, if your server path is a subfolder of another mounted mount point, this 
// will not work properly.
int check_mounts( char* server_path )
{
    int result = FALSE;
    const char* mounts = "/proc/mounts";
    const int SIZE = 4096;
    char line[SIZE];

    FILE* file = fopen( mounts, "r");
    
    if ( file != NULL )
    {
        while( fgets( line, SIZE, file ) != NULL && result != TRUE )
        {
            if ( NULL != strstr( line, server_path ) )
                result = TRUE;
        }

        fclose( file );
    }

    if ( result )
        write_output( "connection_monitor: server mounted" );
    else
            write_output( "connection_monitor: server NOT mounted" );
    return result;
}

// Returns 0 if connected, non-zero if not 
// (non-zero value will be an error code)
int check_availability( char* server_path )
{
    int result = 0;

    char* ls = "ls";
    int length = strlen( ls ) + 2 + strlen( server_path ) + 2;
    char* cmd = (char*)malloc( length );

    sprintf( cmd, "%s \"%s\"", ls, server_path );

    int mounted = check_mounts( server_path );

    if ( mounted )
        result = system( cmd );
    else
        result = ENOTCONN;
    report_error( "check_availability: ", result );
    free( cmd );

    return result;
}

void set_is_connected( struct flache_vol_t* volume, int val )
{
    pthread_mutex_lock( &volume->write_lock );
    volume->is_connected = val;
    pthread_mutex_unlock( &volume->write_lock );
}

/* 
 * This is the server_check thread start point. 
 */
void *monitor_server_status( void* thread_info )
{
    time_t start_time, total_time;
    int status, i;
    int error = FALSE;
    struct timer_thread_info* info = (struct timer_thread_info*) thread_info; 
    struct flache_vol_t* volume = info->volume;
    int *cancel_thread = info->cancel;
    struct file_entry_list_t* list = info->list;

    while ( !*cancel_thread )
    {
        sleep( DEFAULT_TIMER_SLEEP );

        if ( !*cancel_thread && !volume->is_connected )
        {
            status = check_availability( volume->server_path );
    
            if( status == 0 )
            {
                write_output( "connection_monitor: server connected!" );
            
                start_time = time( NULL );

                set_is_connected( volume, TRUE );

                lock_list( list );

                for(i = list->file_count - 1; i >= 0 && !error; i--)
                {
                    struct file_entry_t* file;
                    file = list->entries[i];
                    
                    lock_entry( file );

                    struct stat st;
                    if(stat(file->flash_path,&st) == 0)
                    {
                        if( file->handle_count == 0 && file->dirty == TRUE)
                        {
                            write_output2( "connection_monitor: file dirty: ", file->path );
                            int ret = perform_rsync( file->flash_path, file->server_path, FALSE );

                            // if failed, all we know is that it's still dirty
                            if( 0 == ret )
                                file->dirty = FALSE;

                            if ( ENOTCONN == ret )
                            {
                                error = TRUE;
                                set_is_connected( volume, FALSE );
                            } 
                        }
                        else
                            write_output2( "connection_monitor: file NOT dirty: ", file->path );

                        unlock_entry( file );
                    }
                    else //remove nonexistant file from list
                    {
                        remove_file( list, file );
                        _free_entry( file ); //unlocks file
                    }
                } // end for

                unlock_list( list );    

                total_time = time( NULL ) - start_time;

                if ( DEBUG )
                {
                    char msg[256];
                    sprintf( msg, "connection_monitor: reconnect time: %lu", (unsigned long)total_time );
                    write_output( msg );
                }
            } // end if( status != -1 && status != ENOTCONN )  
        } // end if ( !*cancel_thread && !volume->is_connected )
    } // end while ( !*cancel_thread )

    return NULL;
}

